/*
 * Adaline.cpp
 *
 *  Created on: 09-may-2009
 *      Author: Luis
 */

#include "Adaline.h"

using namespace std;

Adaline::Adaline() {
	ini = 0;
	cantNeuronas = 1;
	cantRasgosE = 2;
	cantRasgosS = 1;
	numIteraciones = 1000;
}

Adaline::~Adaline() {

}

void Adaline::inicializar(const char *filename){
	ifstream arch;
	arch.open(filename);
	arch>>tasaAprendizaje;
	arch>>numIteraciones;
	arch>>tipoEntrenamiento;
	arch>>cantNeuronas;
}

void Adaline::cargarEntrada(const char *filename){
	ifstream arch;
	arch.open(filename);
	arch>>cantPatrones;
	arch>>cantRasgosE;
	patron = new double*[cantPatrones];
	esperado = new double[cantPatrones];
	for (int n = 0; n < cantPatrones; n++){
		patron[n] = new double[cantRasgosE];
		for (int r = 0; r < cantRasgosE; r++){
			arch>>patron[n][r];
		}
	}
	for (int e = 0; e < cantPatrones;e++){
		//for (int r = 0; r < cantRasgosS; r++){		// Para mas de un rasgo de salida!
			arch>>esperado[e];
		//}												// Idem.
	}
}

void Adaline::ejecutar() {
	int p, n, r;
	double correccion = 0.0;
	int iteracion = 0;
	bool continuar = true;
	asignarMemoria();
	do{
		continuar = false;					// Asumimos que la red es perfecta
		if (tipoEntrenamiento == 1){		// Entrenamiento por lotes
			dW = new double*[cantNeuronas];
			for (int n = 0; n < cantNeuronas; n++){
				dW = new double*[cantRasgosE];
				for (int r = 0; r < cantRasgosE; r++){
					dW[n][r] = 0.0;
				}
			}
		}
		for (p = 0; p < cantPatrones; p++){
			for (n = 0; n < cantNeuronas; n++){
				actividad[p][n] = calcularActividad(p, n);
				salida[p][n] = calcularSalida(p, n);
				error = calcularError(p, n);
				if (error != 0){				// Si la red no es perfecta
					continuar = true;			// como asumimos, continua
				}
				for (r = 0; r < cantRasgosE; r++){
					correccion = tasaAprendizaje*error*patron[p][r];
					if (tipoEntrenamiento == 0){
						pesos[n][r] = correccion;
					}
					else{
						dW[n][r] += correccion;		// Acumula las correcciones
					}
				}
			}
		}
		if (tipoEntrenamiento == 1){
			for (n = 0; n < cantNeuronas; n++){
				for (r = 0; r < cantRasgosE; r++){
					pesos[n][r] += dW[n][r];		// Corrige con el acumulado
				}
			}
		}
		delete dW;
		iteracion++;
	}while (continuar || iteracion == numIteraciones);
}

double Adaline::calcularActividad(int _patron, int neurona){
	double salida = 0.0;
	int rasgo;
	for (rasgo = 0; rasgo < cantRasgosE; rasgo++){
		salida += patron[_patron][rasgo] * pesos[neurona][rasgo];
	}
	return salida;
}

double Adaline::calcularSalida(int patron, int neurona){
	return fSigmoide(actividad[patron][neurona]);
}

/*
 * Funcion para Calcular los Wr,k
 * 		r = Patron
 * 		k = Neurona
 *
 */
double Adaline::calcularError(int patron, int neurona){
	double error = 0.0;
	int rasgo;
	for (rasgo = 0; rasgo < cantRasgosS; rasgo++){
		error += (esperado[patron] - salida[patron][rasgo])*
														salida[patron][rasgo]*
														(1-salida[patron][rasgo]);
	}
	return error;
}

void Adaline::asignarMemoria(){
	pesos = new double*[cantNeuronas];
	for(int neurona = 0; neurona < cantNeuronas; neurona++){
		pesos[neurona] = new double[cantRasgosE];
		for (int rasgo = 0; rasgo < cantRasgosE; rasgo++){
			pesos[neurona][rasgo]= aleatorioA(-0.3 , 0.3);
		}
	}
	actividad = new double*[cantPatrones];
	salida = new double*[cantPatrones];
	for (int p = 0; p < cantPatrones; p++){
		actividad[p] = new double[cantNeuronas];
		salida[p] = new double[cantNeuronas];
	}
}
